package com.pactera.asmp.server.utils;

import com.pactera.asmp.server.entity.dbc.Message;
import com.pactera.asmp.server.entity.dbc.Signal;

import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ProjectName: tlsserver
 * @Package com.pactera.asmp.server.utils
 * @ClassName: DbcParseUtil
 * @Description: dbc 文件解析成 pojo
 * @Date 2020/06/08 17:29
 * @Author lvzhiqiang
 * @Version 1.0
 */
@Component
public class DbcParseUtil {
    private final String BO_REGEX = "BO_ (\\d{1,4}) (\\S+): (\\d{1}) ([\\S]+)";
    private final String SG_REGEX = "SG_ (\\S+)( [mM]\\d{1,4}){0,1} : (\\d{1,2})\\|(\\d{1,2})@([01]{1})[\\+\\-] \\(([0-9.\\-eE\\+]+),([0-9.\\-eE\\+]+)\\) \\[([0-9.\\-eE\\+]+)\\|([0-9.\\-eE\\+]+)\\] \"([\\S ]{0,})\"  (Vector__XXX|[\\S]+)";
    private final String BA_REGEX = "BA_ \"GenMsgCycleTime\" BO_ (\\d+) (\\d+);";
    private final String VAL_TABLE_REGEX = "VAL_TABLE_ ([0-9a-zA-Z_]+) (\\d{0,8} \"[\\S ]+\" )+;";

//    public static void main(String[] args) throws IOException {
//        File file = new File("C:\\Users\\Pactera\\Desktop\\dbc\\test.dbc");
//        InputStream is = new FileInputStream(file);
//        System.out.println(JSONObject.toJSONString(new DbcParseUtil().parse(is), SerializerFeature.WriteMapNullValue));
//    }

    /**
     * 解析 dbc 文件
     * @param is
     * @return
     * @throws IOException
     */
    public List<Message> parse(InputStream is) throws IOException {
        // 返回值
        List<Message> messages = new ArrayList<>();
        // BA 数据， key->messageID， value->period
        Map<Long, Long> baMap = new HashMap<>();

        Pattern boPattern = Pattern.compile(BO_REGEX);
        Pattern sgPattern = Pattern.compile(SG_REGEX);
        Pattern baPattern = Pattern.compile(BA_REGEX);
//        Pattern valTablePattern = Pattern.compile(VAL_TABLE_REGEX);

        BufferedReader in = new BufferedReader(new InputStreamReader(is));
        String line = "";
        while (null != (line = in.readLine())) {
            // BO 和 SG
            Matcher boMatcher = boPattern.matcher(line);
            if(boMatcher.find()){
                messages.add(this.handleBo(in, boMatcher, sgPattern));
                continue;
            }
            // BA
            Matcher baMatcher = baPattern.matcher(line);
            if (baMatcher.find()) {
                baMap.put(Long.parseLong(baMatcher.group(1)), Long.parseLong(baMatcher.group(2)));
                continue;
            }
            // VAL_TABLE TODO: 暂不需要
//            Matcher valTableMatcher = valTablePattern.matcher(line);
//            if (valTableMatcher.find()) {
//
//            }
        }
        IOUtils.closeQuietly(in);
        // 将 BA 里的时间周期赋值到 BO 中
        for (int i = 0; i < messages.size(); i++) {
            Message msg = messages.get(i);
            msg.setPeriod(baMap.get(msg.getMessageID()));
            msg.setId(i);
            List<Signal> signals = msg.getSignals();
            for (int j = 0; j < signals.size(); j++) {
                Signal signal = signals.get(j);
                signal.setId(j);
            }
        }
        return messages;
    }

    /**
     * 读取 BO、SG 数据
     * @param in
     * @param boMatcher
     * @return
     * @throws IOException
     */
    private Message handleBo(BufferedReader in, Matcher boMatcher, Pattern sgPattern) throws IOException {
        // 整理 BO 行数据
        Message message = new Message();
        message.setMessageID(Long.parseLong(boMatcher.group(1)));
        message.setMessageName(boMatcher.group(2));
        message.setMessageLen(Integer.parseInt(boMatcher.group(3)));
        message.setTx(boMatcher.group(4));

        // 整理 SG 行数据
        String line = "";
        List<Signal> signals = new ArrayList<>();
        while (null != (line = in.readLine())) {
            Matcher sgMatcher = sgPattern.matcher(line);
            // 未匹配时跳出 while
            if (!sgMatcher.find()) {
                break;
            }
            sgMatcher.reset();
            while (sgMatcher.find()) {
                Signal signal = new Signal();
                signal.setSignalName(sgMatcher.group(1));
                signal.setMultiplexer(sgMatcher.group(2));
                signal.setStartBit(Integer.parseInt(sgMatcher.group(3)));
                signal.setSignalLen(Integer.parseInt(sgMatcher.group(4)));
                signal.setValueType(Integer.parseInt(sgMatcher.group(5)));
                signal.setFactor(Double.parseDouble(sgMatcher.group(6)));
                signal.setOffset(Double.parseDouble(sgMatcher.group(7)));
                signal.setMin(Double.parseDouble(sgMatcher.group(8)));
                signal.setMax(Double.parseDouble(sgMatcher.group(9)));
                signal.setUnit(sgMatcher.group(10));
                signal.setRx(sgMatcher.group(11));
                signals.add(signal);
            }
        }
        message.setSignals(signals);
        return message;
    }
}
